package gobelinmaker.scripting;

import bsh.EvalError;
import bsh.Interpreter;
import gobelinmaker.client.CopressedFileFilter;
import gobelinmaker.client.Dialogs;
import gobelinmaker.client.KanavaPanel;
import gobelinmaker.client.UncopressedFileFilter;
import gobelinmaker.data.Kanava;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

/**
 * Szkriptszerkesztő panel.
 *
 * @see <a href="http://www.beanshell.org/">http://www.beanshell.org/</a>
 * @author imruf84
 */
public class ScriptEditorPanel extends javax.swing.JPanel {

    /**
     * Kanavapanel.
     */
    private final KanavaPanel kp;
    /**
     * Interpreter.
     */
    private Interpreter interpreter;
    /**
     * API.
     */
    private KanavaAPI api;
    /**
     * Kód futtatását végző szál.
     */
    private Thread runCodeThread;

    /**
     * Konstruktor.
     *
     * @param kp kanavapanel
     */
    public ScriptEditorPanel(final KanavaPanel kp) {

        this.kp = kp;
        initComponents();

        // HACK: - amíg nem tudom normálisan megszakítani a kód futását, addig felesleges megjeleníteni ez erre szolgáló gombot
        this.cancelRunButton.setVisible(false);

        // Alapesetben nem látszik a töltőpanel.
        loadingPanel.setVisible(false);

        // Kimenet betűtípusának a beállítása.
        try {
            Font font = Font.createFont(Font.TRUETYPE_FONT, getClass().getResourceAsStream("/fonts/cour.ttf")).deriveFont(Font.PLAIN, 14);
            this.codeTextArea.setFont(font);
        } catch (FontFormatException | IOException ex) {
            System.err.println(ex.getLocalizedMessage());
        }

        // Szkript szövegének a változásának a figyelése.
        this.codeTextArea.getDocument().addDocumentListener(
                new DocumentListener() {
                    @Override
                    public void insertUpdate(DocumentEvent de) {
                        kp.getKanava().toModified();
                    }

                    @Override
                    public void removeUpdate(DocumentEvent de) {
                        kp.getKanava().toModified();
                    }

                    @Override
                    public void changedUpdate(DocumentEvent de) {
                        kp.getKanava().toModified();
                    }
                });

        // Interpreter inicializálása.
        initInterpreter();
    }

    /**
     * Interpreter inicializálása.
     */
    private void initInterpreter() {
        try {

            // Interpreter létrehozása.
            interpreter = new Interpreter();

            // Kanava tárolása.
            this.api = new KanavaAPI(this.kp, this.outTextPane);
            interpreter.set("api", this.api);
            interpreter.set("thread", this.runCodeThread);

            // Kimeneti ablak tárolója.
            this.api.clearOutput();

            // Függvények létrehozása.
            interpreter.eval("print(s){api.writeMessage(s);};");
            interpreter.eval("println(s){print(s+\"\\n\");};");
            interpreter.eval("println(){println(\"\");};");
            interpreter.eval("warning(s){api.writeWarrningMessage(s);};");
            interpreter.eval("error(s){api.writeErrorMessage(s);};");
            interpreter.eval("clear(s){api.clearOutput();};");

            interpreter.eval("rowsCount(){api.rowsCount();};");
            interpreter.eval("columnsCount(){api.columnsCount();};");

            interpreter.eval("addColor(s,r,g,b){api.addColor(s,r,g,b);};");
            interpreter.eval("removeColor(s){api.removeColor(s);};");
            interpreter.eval("setHoleColor(r,c,s){api.setHoleColor(r,c,s);};");
            interpreter.eval("clearHoleColor(r,c){api.clearHoleColor(r,c);};");

            interpreter.eval("appendStitch(s,pr,pc,mode){api.appendStitch(s,pr,pc,mode);};");
            interpreter.eval("reverseStitch(r,c){api.reverseStitch(r,c);};");
            interpreter.eval("removeLastStitch(s){api.removeLastStitch(s);};");

        } catch (EvalError ex) {
            Dialogs.showOpenFailedMessageDialog(this, ex.getLocalizedMessage());
        }
    }

    /**
     * Kód futtatása.
     */
    public void runCode() {
        loadingPanel.setVisible(true);
        runCodeButton.setEnabled(false);
        kp.setEnabled(false);

        initInterpreter();

        try {
            interpreter.eval(codeTextArea.getText());
        } catch (EvalError ex) {
            api.writeErrorMessage(ex.toString());
        }

    }

    /**
     * Kód futásának befejezése.
     */
    public void stopCode() {
        kp.setEnabled(true);
        runCodeButton.setEnabled(true);
        loadingPanel.setVisible(false);
    }

    /**
     * Kód futásának megszakítása.
     */
    public void cancelCode() {
        if (!runCodeThread.isInterrupted()) {
            // BUG: - a szál leáll, de a szkript fut tovább
            runCodeThread.interrupt();
        }
        stopCode();
    }

    /**
     * Szkript forráskódjának a megadása.
     *
     * @param script szkript forráskódja
     */
    public void setSourceCode(String script) {
        this.codeTextArea.setText(script);
    }

    /**
     * Forráskód lekérdezése.
     *
     * @return forráskód szövege
     */
    public String getSourceCode() {
        return this.codeTextArea.getText();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        toolsPanel = new javax.swing.JPanel();
        runCodeButton = new javax.swing.JButton();
        openButton = new javax.swing.JButton();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        codeTextArea = new javax.swing.JTextArea();
        outPanel = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        outTextPane = new javax.swing.JTextPane();
        loadingPanel = new javax.swing.JPanel();
        jProgressBar1 = new javax.swing.JProgressBar();
        cancelRunButton = new javax.swing.JButton();

        setMinimumSize(new java.awt.Dimension(150, 100));
        setLayout(new java.awt.BorderLayout());

        toolsPanel.setLayout(new java.awt.BorderLayout());

        runCodeButton.setMnemonic(KeyEvent.VK_R);
        runCodeButton.setText("Futtatás");
        runCodeButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                runCodeButtonActionPerformed(evt);
            }
        });
        toolsPanel.add(runCodeButton, java.awt.BorderLayout.LINE_START);

        openButton.setText("Megnyitás...");
        openButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openButtonActionPerformed(evt);
            }
        });
        toolsPanel.add(openButton, java.awt.BorderLayout.LINE_END);

        add(toolsPanel, java.awt.BorderLayout.PAGE_START);

        jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        jSplitPane1.setResizeWeight(0.9);
        jSplitPane1.setMinimumSize(new java.awt.Dimension(38, 90));

        codeTextArea.setColumns(1);
        codeTextArea.setRows(1);
        codeTextArea.setMinimumSize(new java.awt.Dimension(6, 6));
        jScrollPane1.setViewportView(codeTextArea);

        jSplitPane1.setLeftComponent(jScrollPane1);

        outPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Kimenet"));
        outPanel.setMinimumSize(new java.awt.Dimension(36, 60));
        outPanel.setPreferredSize(new java.awt.Dimension(100, 60));
        outPanel.setLayout(new java.awt.BorderLayout());

        outTextPane.setEditable(false);
        jScrollPane3.setViewportView(outTextPane);

        outPanel.add(jScrollPane3, java.awt.BorderLayout.CENTER);

        loadingPanel.setLayout(new javax.swing.BoxLayout(loadingPanel, javax.swing.BoxLayout.LINE_AXIS));

        jProgressBar1.setIndeterminate(true);
        loadingPanel.add(jProgressBar1);

        cancelRunButton.setText("Mégsem");
        cancelRunButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancelRunButtonActionPerformed(evt);
            }
        });
        loadingPanel.add(cancelRunButton);

        outPanel.add(loadingPanel, java.awt.BorderLayout.PAGE_END);

        jSplitPane1.setRightComponent(outPanel);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void runCodeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runCodeButtonActionPerformed
        // Kód futtatását végző szál létrehozása.
        this.runCodeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                runCode();
                stopCode();
            }
        });
        this.runCodeThread.start();
    }//GEN-LAST:event_runCodeButtonActionPerformed

    private void cancelRunButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelRunButtonActionPerformed
        this.cancelCode();
    }//GEN-LAST:event_cancelRunButtonActionPerformed

    private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
        JFileChooser fc = new JFileChooser();
        fc.addChoosableFileFilter(new UncopressedFileFilter());
        fc.setFileFilter(new CopressedFileFilter());
        fc.setAcceptAllFileFilterUsed(false);

        int m = fc.showOpenDialog(this);
        if (m == JFileChooser.APPROVE_OPTION) {
            String fileName = fc.getSelectedFile().getAbsolutePath();
            Kanava k = new Kanava(0, 0, false);
            try {
                k.open(fileName);
                String sc = k.getScriptSourceCode();
                if (!sc.isEmpty()) {
                    this.setSourceCode(sc);
                }
            } catch (IOException ex) {

                Dialogs.showOpenFailedMessageDialog(this, ex.getLocalizedMessage());

            }
        }
    }//GEN-LAST:event_openButtonActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton cancelRunButton;
    public javax.swing.JTextArea codeTextArea;
    private javax.swing.JProgressBar jProgressBar1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JPanel loadingPanel;
    private javax.swing.JButton openButton;
    private javax.swing.JPanel outPanel;
    private javax.swing.JTextPane outTextPane;
    private javax.swing.JButton runCodeButton;
    private javax.swing.JPanel toolsPanel;
    // End of variables declaration//GEN-END:variables
}
